package com.deluxelx.soul.inn.service.task;

import cn.hutool.core.util.StrUtil;
import com.deluxelx.soul.inn.bean.article.Article;
import com.deluxelx.soul.inn.bean.counselor.Counselor;
import com.deluxelx.soul.inn.bean.course.Course;
import com.deluxelx.soul.inn.bean.question.Question;
import com.deluxelx.soul.inn.bean.relation.FollowRelation;
import com.deluxelx.soul.inn.common.util.RedisUtil;
import com.deluxelx.soul.inn.service.article.ArticleService;
import com.deluxelx.soul.inn.service.common.FollowRelationService;
import com.deluxelx.soul.inn.service.counselor.CounselorService;
import com.deluxelx.soul.inn.service.course.CourseService;
import com.deluxelx.soul.inn.service.question.QuestionService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

import static com.deluxelx.soul.inn.common.constant.CounselorConstant.*;
import static com.deluxelx.soul.inn.common.constant.ArticleConstant.*;
import static com.deluxelx.soul.inn.common.constant.CourseConstant.*;
import static com.deluxelx.soul.inn.common.constant.QuestionConstant.*;
import static com.deluxelx.soul.inn.common.constant.UserConstant.USER_CACHE_KEY_PREFIX;

/**
 * 关注、点赞、收藏等定时任务
 *      保证 redis 和 Mysql 数据一致性
 *
 * @author: zihao.liao
 * @date: 2024/4/13 22:53
 */
@Component
@Slf4j
public class FollowTask {

    @XxlJob(value = "FollowCounselorHandler")
    public void followCounselorHandler() {
        log.info("---------- 【咨询师】关注相关数据同步开始 ----------");
        followCounselorTask();
        log.info("---------- 【咨询师】关注相关数据同步结束 ----------");
    }

    @XxlJob(value = "FollowCourseHandler")
    public void followCourseHandler() {
        log.info("---------- 【课程】收藏相关数据同步开始 ----------");
        followCourseTask();
        log.info("---------- 【课程】收藏相关数据同步结束 ----------");
    }

    @XxlJob(value = "FollowArticleHandler")
    public void followArticleHandler() {
        log.info("---------- 【文章】收藏相关数据同步开始 ----------");
        followArticleTask();
        log.info("---------- 【文章】收藏相关数据同步结束 ----------");
    }

    @XxlJob(value = "FollowQuestionHandler")
    public void followQuestionHandler() {
        log.info("---------- 【心理问答】点赞相关数据同步开始 ----------");
        followQuestionTask();
        log.info("---------- 【心理问答】点赞相关数据同步结束 ----------");
    }

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private FollowRelationService followRelationService;

    @Resource
    private CounselorService counselorService;

    @Resource
    private CourseService courseService;

    @Resource
    private ArticleService articleService;

    @Resource
    private QuestionService questionService;

    /**
     * 心理问答点赞相关数据同步
     * 0 0 1 * * ?
     * 每天凌晨1点执行一次
     **/
    public void followQuestionTask() {
        try {
            // 1. 获取 redis 中需要同步的数据
            // 1.1 用户 - 心理问答关注关系
            List<String> keys1 = redisUtil.scanKeys(questionTaskPattern1);
            // 1.2 心理问答点赞数量
            List<String> keys2 = redisUtil.scanKeys(questionTaskPattern2);
            // 1.3 心理问答阅读量
            List<String> keys3 = redisUtil.scanKeys(questionTaskPattern3);
            // 2. 遍历 redis 中的数据，同步到 Mysql 中
            // 2.1 用户 - 心理问答
            for (String key : keys1) {
                String[] split = key.split(StrUtil.COLON);
                String userId = split[0].substring(USER_CACHE_KEY_PREFIX.length());
                String questionId = split[1].substring(QUESTION_CACHE_KEY_PREFIX.length());
                Integer flag = redisUtil.get(key, Integer.class);
                Integer count = followRelationService.lambdaQuery()
                        .eq(FollowRelation::getUserId, userId)
                        .eq(FollowRelation::getQuestionId, questionId)
                        .count();
                if (count > 0) {
                    followRelationService.lambdaUpdate()
                            .set(FollowRelation::getDeleteFlag, flag)
                            .eq(FollowRelation::getUserId, userId)
                            .eq(FollowRelation::getQuestionId, questionId)
                            .update();
                } else {
                    FollowRelation followRelation = new FollowRelation();
                    followRelation.setUserId(userId);
                    followRelation.setQuestionId(questionId);
                    followRelationService.save(followRelation);
                }
            }
            // 2.2 心理问答点赞
            for (String key : keys2) {
                String[] split = key.split(StrUtil.COLON);
                String questionId = split[1];
                Integer likeNum = redisUtil.get(key, Integer.class);
                questionService.lambdaUpdate()
                        .set(Question::getLikeNum, likeNum)
                        .eq(Question::getId, questionId)
                        .update();
            }
            // 2.3 心理问答阅读量
            for (String key : keys3) {
                String[] split = key.split(StrUtil.COLON);
                String questionId = split[1];
                Integer readNum = redisUtil.get(key, Integer.class);
                questionService.lambdaUpdate()
                        .set(Question::getReadNum, readNum)
                        .eq(Question::getId, questionId)
                        .update();
            }
        } catch (Exception e) {
            log.error("【心理问答】点赞相关数据同步失败：" + e.getMessage());
        }
    }
    /**
     * 咨询师关注相关数据同步
     * 0 0 2 * * ?
     * 每天凌晨2点执行一次
     **/
    public void followCounselorTask() {
        try {
            List<String> keys1 = redisUtil.scanKeys(counselorTaskPattern1);
            List<String> keys2 = redisUtil.scanKeys(counselorTaskPattern2);
            for (String key : keys1) {
                String[] split = key.split(StrUtil.COLON);
                String userId = split[0].substring(USER_CACHE_KEY_PREFIX.length());
                String counselorId = split[1].substring(COUNSELOR_CACHE_KEY_PREFIX.length());
                Integer flag = redisUtil.get(key, Integer.class);
                Integer count = followRelationService.lambdaQuery()
                        .eq(FollowRelation::getUserId, userId)
                        .eq(FollowRelation::getCounselorId, counselorId)
                        .count();
                if (count > 0) {
                    followRelationService.lambdaUpdate()
                            .set(FollowRelation::getDeleteFlag, flag)
                            .eq(FollowRelation::getUserId, userId)
                            .eq(FollowRelation::getCounselorId, counselorId)
                            .update();
                } else {
                    FollowRelation followRelation = new FollowRelation();
                    followRelation.setUserId(userId);
                    followRelation.setCounselorId(counselorId);
                    followRelationService.save(followRelation);
                }
            }
            for (String key : keys2) {
                String[] split = key.split(StrUtil.COLON);
                String counselorId = split[1];
                Integer fansCount = redisUtil.get(key, Integer.class);
                counselorService.lambdaUpdate()
                        .set(Counselor::getFansCount, fansCount)
                        .eq(Counselor::getId, counselorId).update();
            }
        } catch (Exception e) {
            log.error("【咨询师】关注相关数据同步失败：" + e.getMessage());
        }
    }
    /**
     * 课程收藏相关数据同步
     * 0 0 3 * * ?
     * 每天凌晨3点执行一次
     **/
    public void followCourseTask() {
        try {
            // 1. 获取 redis 中需要同步的数据
            // 1.1 用户 - 课程关注关系
            List<String> keys1 = redisUtil.scanKeys(courseTaskPattern1);
            // 1.2 课程收藏数量
            List<String> keys2 = redisUtil.scanKeys(courseTaskPattern2);
            // 1.3 课程播放量
            List<String> keys3 = redisUtil.scanKeys(courseTaskPattern3);
            // 2. 遍历 redis 中的数据，同步到 Mysql 中
            // 2.1 用户 - 咨询师
            for (String key : keys1) {
                String[] split = key.split(StrUtil.COLON);
                String userId = split[0].substring(USER_CACHE_KEY_PREFIX.length());
                String courseId = split[1].substring(COURSE_CACHE_KEY_PREFIX.length());
                Integer flag = redisUtil.get(key, Integer.class);
                Integer count = followRelationService.lambdaQuery()
                        .eq(FollowRelation::getUserId, userId)
                        .eq(FollowRelation::getCourseId, courseId)
                        .count();
                if (count > 0) {
                    followRelationService.lambdaUpdate()
                            .set(FollowRelation::getDeleteFlag, flag)
                            .eq(FollowRelation::getUserId, userId)
                            .eq(FollowRelation::getCourseId, courseId)
                            .update();
                } else {
                    FollowRelation followRelation = new FollowRelation();
                    followRelation.setUserId(userId);
                    followRelation.setCourseId(courseId);
                    followRelationService.save(followRelation);
                }
            }
            // 2.2 课程收藏
            for (String key : keys2) {
                String[] split = key.split(StrUtil.COLON);
                String courseId = split[1];
                Integer collectNum = redisUtil.get(key, Integer.class);
                courseService.lambdaUpdate()
                        .set(Course::getCollectNum, collectNum)
                        .eq(Course::getId, courseId)
                        .update();
            }
            // 2.3 课程播放
            for (String key : keys3) {
                String[] split = key.split(StrUtil.COLON);
                String courseId = split[1];
                Integer playNum = redisUtil.get(key, Integer.class);
                courseService.lambdaUpdate()
                        .set(Course::getPlayNum, playNum)
                        .eq(Course::getId, courseId)
                        .update();
            }
        } catch (Exception e) {
            log.error("【课程】收藏相关数据同步失败：" + e.getMessage());
        }
    }
    /**
     * 课程收藏相关数据同步
     * 0 0 4 * * ?
     * 每天凌晨4点执行一次
     **/
    public void followArticleTask() {
        try {
            // 1. 获取 redis 中需要同步的数据
            // 1.1 用户 - 文章关注关系
            List<String> keys1 = redisUtil.scanKeys(articleTaskPattern1);
            // 1.2 文章收藏数量
            List<String> keys2 = redisUtil.scanKeys(articleTaskPattern2);
            // 1.3 文章阅读量
            List<String> keys3 = redisUtil.scanKeys(articleTaskPattern3);
            // 2. 遍历 redis 中的数据，同步到 Mysql 中
            // 2.1 用户 - 文章
            for (String key : keys1) {
                String[] split = key.split(StrUtil.COLON);
                String userId = split[0].substring(USER_CACHE_KEY_PREFIX.length());
                String articleId = split[1].substring(ARTICLE_CACHE_KEY_PREFIX.length());
                Integer flag = redisUtil.get(key, Integer.class);
                Integer count = followRelationService.lambdaQuery()
                        .eq(FollowRelation::getUserId, userId)
                        .eq(FollowRelation::getArticleId, articleId)
                        .count();
                if (count > 0) {
                    followRelationService.lambdaUpdate()
                            .set(FollowRelation::getDeleteFlag, flag)
                            .eq(FollowRelation::getUserId, userId)
                            .eq(FollowRelation::getArticleId, articleId)
                            .update();
                } else {
                    FollowRelation followRelation = new FollowRelation();
                    followRelation.setUserId(userId);
                    followRelation.setArticleId(articleId);
                    followRelationService.save(followRelation);
                }
            }
            // 2.2 文章收藏
            for (String key : keys2) {
                String[] split = key.split(StrUtil.COLON);
                String articleId = split[1];
                Integer collectNum = redisUtil.get(key, Integer.class);
                articleService.lambdaUpdate()
                        .set(Article::getCollectNum, collectNum)
                        .eq(Article::getId, articleId)
                        .update();
            }
            // 2.3 文章阅读量
            for (String key : keys3) {
                String[] split = key.split(StrUtil.COLON);
                String articleId = split[1];
                Integer readNum = redisUtil.get(key, Integer.class);
                articleService.lambdaUpdate()
                        .set(Article::getReadNum, readNum)
                        .eq(Article::getId, articleId)
                        .update();
            }
        } catch (Exception e) {
            log.error("【文章】收藏相关数据同步失败：" + e.getMessage());
        }
    }

}
